/******************************************************************************* 
 * Copyright (c) 2008 xored software, Inc.  
 * 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution, and is available at 
 * http://www.eclipse.org/legal/epl-v10.html  
 * 
 * Contributors: 
 *     xored software, Inc. - initial API and Implementation (Yuri Strot) 
 *******************************************************************************/
package com.xored.glance.internal.st;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;

import com.xored.glance.core.IMatch;
import com.xored.glance.core.ITextBlock;
import com.xored.glance.core.ITextContainer;
import com.xored.glance.core.StyleList;

/**
 * @author Yuri Strot
 * 
 */
public class StyledTextControl implements ITextContainer {

	private StyledText text;
	private StyledTextBlock[] blocks;
	private RangeGroup[] previous;

	public StyledTextControl(StyledText text) {
		this.text = text;
		blocks = new StyledTextBlock[] { new StyledTextBlock() };
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextControl#dispose()
	 */
	public void dispose() {
		clearHighlight();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextControl#getText()
	 */
	public ITextBlock[] getText() {
		return blocks;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.xored.glance.core.ITextContainer#getFont()
	 */
	public Font getFont() {
		return text.getFont();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#select(com.xored.glance.core.IMatch)
	 */
	public void select(IMatch match) {
		if (match != null) {
			text.setSelection(match.getOffset(), match.getOffset()
					+ match.getLength());
		} else {
			int x = text.getSelection().x;
			text.setSelection(x, x);
		}
	}

	protected void clearHighlight() {
		if (previous != null && previous.length > 0) {
			for (int i = 0; i < previous.length; i++) {
				RangeGroup group = previous[i];
				text.replaceStyleRanges(group.getStart(), group.getEnd()
						- group.getStart(), new StyleRange[0]);
				StyleRange[] ranges = group.getRanges();
				for (StyleRange range : ranges) {
					text.replaceStyleRanges(range.start, range.length,
							new StyleRange[] { range });
				}
			}
		}
		previous = null;
	}

	protected Color getBgHighlight() {
		return text.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
	}

	protected Color getFgHighlight() {
		return text.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.xored.glance.core.ITextControl#show(com.xored.glance.core.IMatch[])
	 */
	public void show(IMatch[] matches) {
		clearHighlight();
		previous = new RangeGroup[matches.length];
		for (int i = 0; i < matches.length; i++) {
			IMatch match = matches[i];
			int index = match.getOffset();
			int latIndex = index + match.getLength();
			StyleRange[] matchRanges = text.getStyleRanges(index, match
					.getLength());
			List<StyleRange> ranges = new ArrayList<StyleRange>();
			for (StyleRange styleRange : matchRanges) {
				ranges.add(styleRange);
				if (styleRange.length < 0) {
					continue;
				}
				StyleRange newStyleRangerange = new StyleRange(
						styleRange.start, styleRange.length, getFgHighlight(),
						getBgHighlight(), styleRange.fontStyle);
				if (styleRange.start - index > 0)
					text.replaceStyleRanges(index, styleRange.start - index,
							new StyleRange[] { newStyleRangerange });
				text.replaceStyleRanges(styleRange.start, styleRange.length,
						new StyleRange[] { newStyleRangerange });
				index = styleRange.start + styleRange.length;
			}
			if (latIndex - index > 0) {
				StyleRange newStyleRangerange = new StyleRange(index, latIndex
						- index, getFgHighlight(), getBgHighlight());
				text.replaceStyleRanges(index, latIndex - index,
						new StyleRange[] { newStyleRangerange });
			}
			previous[i] = new RangeGroup(match.getOffset(), latIndex, ranges
					.toArray(new StyleRange[ranges.size()]));
		}
	}

	private class StyledTextBlock implements ITextBlock {

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.ITextBlock#createMatch(int, int)
		 */
		public IMatch createMatch(int offset, int length) {
			return new Match(offset, length, this);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.ITextBlock#getText()
		 */
		public String getText() {
			return text.getText();
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.ITextBlock#getStyles()
		 */
		public StyleList getStyles() {
			return new StyleList(text.getStyleRanges());
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.IStyledText#getImage()
		 */
		public Image getImage() {
			return null;
		}

	}

	private class Match implements IMatch {

		private int offset;
		private int length;
		private ITextBlock block;

		public Match(int offset, int length, ITextBlock block) {
			this.offset = offset;
			this.length = length;
			this.block = block;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.IMatch#getLength()
		 */
		public int getLength() {
			return length;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.IMatch#getOffset()
		 */
		public int getOffset() {
			return offset;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.xored.glance.core.IMatch#getTextBlock()
		 */
		public ITextBlock getTextBlock() {
			return block;
		}

	}

}
